/*******************************************************************************
 * Copyright (c) 2008-2009 zhang yuexiang.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 
package org.xfeep.asura.bootstrap;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;

import org.xfeep.asura.core.ComponentDefinition;
import org.xfeep.asura.core.ComponentManager;
import org.xfeep.asura.core.ServiceSpace;
import org.xfeep.asura.core.config.ConfigAdminService;
import org.xfeep.asura.core.logger.CoreLoggerManager;
import org.xfeep.asura.core.util.InlineExecutorService;
import org.xfeep.asura.core.util.SimplePattern;

public class Asura {
	
	ClassLoader classLoader;
	ComponentManager componentManager;
	ExecutorService executorService;
	boolean externExecutorService = false;
	public boolean isExternExecutorService() {
		return externExecutorService;
	}


	public void setExternExecutorService(boolean externExecutorService) {
		this.externExecutorService = externExecutorService;
	}

	boolean started = false;
	List<SimplePattern> componentIngorePatternList = new ArrayList<SimplePattern>();
	
	public synchronized boolean isStarted() {
		return started;
	}


	public ClassLoader getClassLoader() {
		return classLoader;
	}

	public void setClassLoader(ClassLoader classLoader) {
		this.classLoader = classLoader;
	}

	public ComponentManager getComponentManager() {
		return componentManager;
	}

	public void setComponentManager(ComponentManager componentManager) {
		this.componentManager = componentManager;
	}

	public ExecutorService getExecutorService() {
		return executorService;
	}

	public void setExecutorService(ExecutorService executorService) {
		this.executorService = executorService;
	}

	public Asura(){
		this(Thread.currentThread().getContextClassLoader(), new InlineExecutorService());
		this.externExecutorService = false;
	}
	
	public Asura(ClassLoader classLoader){
		this(classLoader, new InlineExecutorService());
		this.externExecutorService = false;
	}
	
	public Asura(ClassLoader classLoader, ExecutorService executorService){
		this.classLoader = classLoader;
		this.executorService = executorService;
		this.externExecutorService = true;
	}
	
	public void addComponentIngorePattern(String pattern){
		componentIngorePatternList.add(new SimplePattern(pattern));
	}
	
	public synchronized void start() {
//		SmartComponentLoader sml = new SmartComponentLoader();
//		sml.addIngoreFilePattern("/System/Library/*");
//		sml.addIngoreFilePattern("*/jre/lib/*");
//		sml.addIngoreFilePattern("*/testbin");
//		sml.addIngoreFilePattern("*/maven.1234965017552/*");
//		sml.addIngoreFilePattern("*/org.eclipse.osgi/bundles/*");
//		long s = System.currentTimeMillis();
//		start(sml);
//		System.out.println("SmartComponentLoader cost: " + (System.currentTimeMillis() - s) + "ms");
		start(new MemoryComponentLoader());
	}
	
	public synchronized void start(ComponentLoader... loaders){
		if (started){
			return;
		}
		componentManager = new ComponentManager(executorService);
		started = true;
		addComponentsFormLoaders(loaders);
		componentManager.openApplicationServiceSpace();
	}
	
	public ServiceSpace getApplicationServiceSpace() {
		return componentManager.getApplicationServiceSpace();
	}


	public synchronized void addComponentsFormLoaders(ComponentLoader... loaders){
		for (ComponentLoader loader : loaders){
			loader.initialize(componentManager);
			List<ComponentDefinition> cdlist;
			try {
				cdlist = loader.getStaticLoadComponents(classLoader);
				if (cdlist != null){
					if (componentIngorePatternList.isEmpty()){
						componentManager.addAll(cdlist);
					}else{
						for (SimplePattern sp : componentIngorePatternList){
							for (ComponentDefinition cd : cdlist){
								if (sp.match(cd.getImplement().getName()) < 0){
									componentManager.add(cd);
								}
							}
						}
					}
				}
				
			} catch (IOException e) {
				CoreLoggerManager.getDefaultLogger().warn("load IO error in loader " + loader, e);
			}
//			for (ComponentDefinition cd : cdlist){
//				System.out.println(cd.getImplement().getName());
//			}
		}
	}
	
	public ConfigAdminService getConfigAdminService() {
		if (!started){
			return null;
		}
		return getApplicationServiceSpace().findService(ConfigAdminService.class);
	}
	
	public synchronized void shutdown(){
		if (!started){
			return;
		}
		started = false;
		componentManager.getApplicationServiceSpace().close();
		if(!externExecutorService){
			executorService.shutdown();
		}
	}
	
	
}
